package info.interactivesystems.gamificationengine.api;
import info.interactivesystems.gamificationengine.api.exeption.ApiError;
import info.interactivesystems.gamificationengine.api.exeption.CredentialException;
import info.interactivesystems.gamificationengine.api.exeption.Notification;
import info.interactivesystems.gamificationengine.api.validation.ValidApiKey;
import info.interactivesystems.gamificationengine.dao.AccountDAO;
import info.interactivesystems.gamificationengine.dao.OrganisationDAO;
import info.interactivesystems.gamificationengine.entities.Account;
import info.interactivesystems.gamificationengine.entities.Organisation;
import info.interactivesystems.gamificationengine.utils.SecurityTools;
import java.util.List;
import javax.ejb.Stateless;
import javax.inject.Inject;
import javax.validation.constraints.NotNull;
import javax.ws.rs.GET;
import javax.ws.rs.HeaderParam;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import org.hibernate.validator.constraints.Email;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.webcohesion.enunciate.metadata.rs.TypeHint;
/**
* An Organisation represents for example a specific company or an association which
* represents a group of people belonging together and which are participating in the
* gamification process.
* An Organisation possessed an generated API key which is needed for all further interactions
* because all database entries are associated with this unique key and so with the respective
* organisation. The API key is uniquely in the whole application. It
* may be changed, for this reason it has no primary key.
* When an Organisation is created it has to be connected with an account. Each organisation
* may be managed by many people, but at least by one who is added to the list of the manager
* of the respective organisation and so also the Account.
* In the response of all requests the account's password isn't returned because of security
* reasons.
*/
@Path("/organisation")
@Stateless
@Produces(MediaType.APPLICATION_JSON)
public class OrganisationApi {
private static final Logger LOGGER = LoggerFactory.getLogger(OrganisationApi.class);
@Inject
OrganisationDAO organisationDao;
@Inject
AccountDAO accountDao;
/**
* Creates a new organisation. The email address and password of one Account are used
* to connect it with this organisation. So the email address and password are mandatory for
* authentication otherwise a warning with the hint for wrong credentials is returned.
* All further Accounts which should be associated to this organisation are added with the
* method addManager.
* In the response the account's password isn't returned because of security reasons.
*
* @param name
* The name of the developer or the manager of the account.
* @param email
* The required valid email address.
* @param password
* Required header parameter associated with the email address.
* @return A Response of Organisation in JSON.
*/
@POST
@Path("/")
@TypeHint(Organisation.class)
public Response create(@QueryParam("name") String name, @QueryParam("email") @NotNull @Email String email,
@HeaderParam("password") @NotNull String password) {
LOGGER.debug("create organisation requested");
String encryptedPassword = SecurityTools.encryptWithSHA512(password);
if (!accountDao.checkCredentials(email, encryptedPassword)) {
throw new CredentialException(email);
}
Organisation organisation = new Organisation(name);
organisation.addManager(accountDao.getAccount(email, encryptedPassword));
organisation.setApiKey(SecurityTools.generateApiKey());
LOGGER.debug("Organisation created");
organisationDao.insertOrganisation(organisation);
return ResponseSurrogate.created(organisation);
}
/**
* Adds a new developer to the organisation's list of manager. The email address and
* password are mandatory for authentication otherwise a warning with the hint for
* wrong credentials is returned. If the manager who should be added is already in the
* list, a message is given with the hint that she/he is already added.
* In the response the account's password isn't returned because of security reasons.
*
* @param manager
* The required valid email address for the new manager.
* @param managerPw
* The required new password of the new maanger.
* @param firstName
* Optionally the first name of the Account's owner can be set.
* @param lastName
* Optionally the last name of the Account's owner can be set.
* @param apiKey
* The API key of the organisation to which the manager belongs to.
* @return A Response of Organisation in JSON.
*/
@POST
@Path("/addManager")
@TypeHint(Organisation.class)
public Response addManager(@QueryParam("manager") @NotNull @Email String manager, @QueryParam("managerPW") @NotNull String managerPw,
@QueryParam("firstName") String firstName, @QueryParam("lastName") String lastName,
@QueryParam("apiKey") @ValidApiKey String apiKey) {
LOGGER.debug("add organisation requested");
Organisation organisation = organisationDao.getOrganisationByApiKey(apiKey);
if(organisation == null){
throw new ApiError(Response.Status.NOT_FOUND, "Organisation %s not found");
}
if (organisation.getManagers().contains(accountDao.getAccount(manager))) {
throw new ApiError(Response.Status.NOT_ACCEPTABLE, "Account %s already in managers list", manager);
}
Account newManager = new Account(manager);
newManager.setPassword(SecurityTools.encryptWithSHA512(managerPw));
newManager.setFirstName(firstName);
newManager.setLastName(lastName);
organisation.addManager(newManager);
return ResponseSurrogate.created(organisation);
}
/**
* Returns all organisations which are associated with the combination of the two
* query parameters. Otherwise an exception is sent that the given credentials are wrong.
* In the response the account's password isn't returned because of security reasons.
*
* @param email
* A required valid email address.
* @param password
* Required header parameter to connect it with the given email address.
* @return A Response as List of Organisations in JSON.
*/
@GET
@Path("/*")
@TypeHint(Organisation[].class)
public Response get(@QueryParam("email") @NotNull @Email String email, @HeaderParam("password") @NotNull String password) {
LOGGER.debug("get organisation requested");
if (!accountDao.checkCredentials(email, SecurityTools.encryptWithSHA512(password))) {
throw new CredentialException(email);
}
List<Organisation> organisation = organisationDao.getAllOrganisations(email);
return ResponseSurrogate.of(organisation);
}
/**
* Returns a specific organisation which id is equal to the transfered path parameter.
* Additionally the email address and the associated password are mandatory and have to be
* correct otherwise an exception is returned that the given credentials are wrong.
* In the response the account's password isn't returned because of security reasons.
*
* @param id
* The path parameter of the organisation, that should be returned.
* @param email
* The valid email address.
* @param password
* Required header parameter to connect it with the given
* email address.
* @return A response of Organisation in JSON.
*/
@GET
@Path("/{id}")
@TypeHint(Organisation.class)
public Response get(@PathParam("id") @NotNull String id, @QueryParam("email") @NotNull @Email String email,
@HeaderParam("password") @NotNull String password) {
LOGGER.debug("get organisation requested");
if (!accountDao.checkCredentials(email, SecurityTools.encryptWithSHA512(password))) {
throw new CredentialException(email);
}
int intId = Integer.parseInt(id);
Organisation organisation = organisationDao.getOrganisation(intId);
return ResponseSurrogate.of(organisation);
}
/**
* Generates an API key for the given organisation which matches the id, email address and the
* associated password. Otherwise an exception is returned that the given credentials are wrong.
* If the API key field is already set the method resets it and replaced it with the new generated
* API key.
* In the response the account's password isn't returned because of security reasons.
*
* @param id
* The path parameter of the organisation, for which the API key should be generated.
* @param email
* The valid email address.
* @param password
* Required header parameter to connect it with the given email address.
* @return A Response of Organisation in JSON.
*/
@PUT
@Path("/{id}/generateapikey")
@TypeHint(Organisation.class)
public Response generateApiKey(@PathParam("id") @NotNull String id, @QueryParam("email") @Email String email,
@HeaderParam("password") @NotNull String password) {
Notification notification = new Notification();
LOGGER.debug("generate api key requested");
if (!accountDao.checkCredentials(email, SecurityTools.encryptWithSHA512(password))) {
throw new CredentialException(email);
}
int intId = Integer.parseInt(id);
Organisation organisation = organisationDao.getOrganisation(intId);
organisation.setApiKey(SecurityTools.generateApiKey());
return ResponseSurrogate.updated(organisation, notification);
}
}